package com.igeek.yygh.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.igeek.yygh.mapper.EldersMapper;
import com.igeek.yygh.model.elders.Elders;
import com.igeek.yygh.result.Result;
import com.igeek.yygh.service.EldersService;
import com.igeek.yygh.vo.PageQueryVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;


/**
 * TODO
 *
 * @author Guzhenghui
 * @since 2024/8/18
 */
@Service
public class EldersServiceImpl extends ServiceImpl<EldersMapper, Elders> implements EldersService {
@Autowired
private EldersMapper eldersMapper;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
    private static final String CACHE_KEY = "eldersLocation";
    private static final String OUT_KEY = "OutLocation";
    private static final Double CENTER_LON = 120.371091; // 中心经度
    private static final Double CENTER_LAT = 31.487928; // 中心纬度
    private static final Double RADIUS = 2000.0; // 半径，单位：米
    private static final double EARTH_RADIUS = 6371; // 地球半径，单位为公里
    @Override
    public Page<Elders> findPage(PageQueryVO vo) {
        Integer currentPage = vo.getCurrentPage();
        Integer pageSize = vo.getPageSize();
        String queryString = vo.getQueryString();
        //封装Page对象
        Page<Elders> page = new Page<>(currentPage , pageSize);
        //封装查询条件
        LambdaQueryWrapper<Elders> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StringUtils.hasLength(queryString) , Elders::getNumberId , queryString)
                .or().like(StringUtils.hasLength(queryString) , Elders::getName , queryString);
        //分页查询数据
        Page<Elders> checkitemPage = this.baseMapper.selectPage(page, lambdaQueryWrapper);
        return checkitemPage;
    }

    @Override
    public Map<String, Object> getElderById(Long id) {
        return eldersMapper.selectElderById(Math.toIntExact(id));
    }

    @Override
    public List<Map<String, Object> > getEldersLocationAll() {
//        return eldersMapper.selectElder();
        String cacheKey = "eldersLocation";
        String outKey="OutLacation";
        List<Map<String, Object>> outList=new ArrayList<Map<String, Object>>();

        ValueOperations<String, Object> valueOps = redisTemplate.opsForValue();

        // 尝试从 Redis 缓存中获取数据
        List<Map<String, Object>> eldersList = (List<Map<String, Object>>) valueOps.get(CACHE_KEY);

        if (eldersList == null) {
            // 数据不在缓存中，从数据库中查询
            eldersList = eldersMapper.selectElder();

            // 将查询结果存储到 Redis 中，设置过期时间（例如，1小时）
            valueOps.set(cacheKey, eldersList, 1, TimeUnit.HOURS);
        }

        for (Map<String, Object> elder : eldersList) {
            String lalo = (String) elder.get("lalo"); // 获取lalo字段
            String[] laloParts = lalo.split(","); // 分割经度和纬度
            Double elderLon = Double.parseDouble(laloParts[0].trim()); // 经度
            Double elderLat = Double.parseDouble(laloParts[1].trim()); // 纬度
            if (distance(CENTER_LON, CENTER_LAT, elderLon,elderLat ) > RADIUS) {
                outList.add(elder);
            }
        }
//        outList.add(eldersList.get(0));
        valueOps.set(OUT_KEY, outList, 1, TimeUnit.HOURS);

        return eldersList;
    }
    public static double distance(double lon1, double lat1, double lon2, double lat2) {
        // 将经纬度转换为弧度
        double lon1Rad = Math.toRadians(lon1);
        double lat1Rad = Math.toRadians(lat1);
        double lon2Rad = Math.toRadians(lon2);
        double lat2Rad = Math.toRadians(lat2);

        // 计算经度和纬度的差值
        double dLon = lon2Rad - lon1Rad;
        double dLat = lat2Rad - lat1Rad;

        // Haversine公式
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                Math.cos(lat1Rad) * Math.cos(lat2Rad) *
                        Math.sin(dLon / 2) * Math.sin(dLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

        // 计算距离
        return EARTH_RADIUS * c*1000;
    }
    // 定期更新缓存的方法，每五分钟执行一次
    @Scheduled(fixedRate = 1* 60 * 1000) // 5分钟（300000毫秒）
    public void updateCache() {
        List<Map<String, Object>> eldersList = eldersMapper.selectElder();
        ValueOperations<String, Object> valueOps = redisTemplate.opsForValue();
        valueOps.set(CACHE_KEY, eldersList, 1, TimeUnit.HOURS); // 设置过期时间
    }
    @Scheduled(fixedRate = 1 * 60 * 1000) // 5分钟（300000毫秒）
    public void updateOutListCache() {
        List<Map<String, Object>> eldersList = eldersMapper.selectElder();
        List<Map<String, Object>> outList = new ArrayList<>();

        // 计算并过滤超出范围的记录
        for (Map<String, Object> elder : eldersList) {
            String lalo = (String) elder.get("lalo"); // 获取lalo字段
            String[] laloParts = lalo.split(","); // 分割经度和纬度
            Double elderLon = Double.parseDouble(laloParts[0].trim()); // 经度
            Double elderLat = Double.parseDouble(laloParts[1].trim()); // 纬度

            if (distance(CENTER_LON, CENTER_LAT, elderLon, elderLat) > RADIUS) {
                outList.add(elder);
            }
        }

        // 将超出范围的记录存储到 Redis 中
        ValueOperations<String, Object> valueOps = redisTemplate.opsForValue();
        valueOps.set(OUT_KEY, outList, 1, TimeUnit.HOURS);
    }
    }








